package com.zimmor.pool;

import java.time.LocalDateTime;
import java.util.concurrent.*;

/**
 * @Author:zimmor
 * @Date: 2023/3/13 17:35
 * @Description
 * @version: 1.0.0
 */

public class ExecutorsNewThreadPool {
    public static void main(String[] args) {
//        newFixedThreadPool();
//        newCachedThreadPool();
//        newSingleThreadExecutor();
        scheduledThreadPool();
//        singleThreadScheduledExecutor();
//        newWorkStealingPool();
    }


    public static void  newFixedThreadPool() {
        //创建一个固定大小的线程池，可控制并发的线程数，超出的线程会在队列中等待
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("当前线程名称：" + Thread.currentThread().getName());

            }
        };
        //用该线程池执行任务有两种方式
        threadPool.submit(runnable);//方式一用submit来执行
        threadPool.execute(runnable);//方式二用execute来执行

    }

    public static void newCachedThreadPool() {
        //创建一个可缓存的线程池，若线程数超过处理所需，缓存一段时间后会回收，若线程数不够，则新建线程
        ExecutorService threadPool = Executors.newCachedThreadPool();
        for (int i = 0; i <100 ; i++) {
            threadPool.execute(() -> {
                System.out.println("当前线程的名称" + Thread.currentThread().getName());
                try {
//                    Thread.sleep(2000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }

    public static void  newSingleThreadExecutor() {

//        从以上代码可以看出 newSingleThreadExecutor 和 newSingleThreadScheduledExecutor 创建的都是单线程池，那么单线程池的意义是什么呢？
//        答：虽然是单线程池，但提供了工作队列，生命周期管理，工作线程维护等功能。


        //创建只有单个线程的线程池，他可以保证任务的先进先出的执行顺序
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            //使用线程池执行任务
            threadPool.execute(() -> {
                System.out.println("线程的名称：" + Thread.currentThread().getName());
            });
        }
    }

    public static void scheduledThreadPool() {
        System.out.println(LocalDateTime.now() + "开始执行");
        //创建可以执行延时任务的线程池
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
        //使用线程池调用延时任务，只执行一次
        /**
         * 参数含义
         * param1 延时的时间
         * param2 配合param1的单位
         */
//        threadPool.schedule(() -> {
//            System.out.println(LocalDateTime.now() + " 线程名称：" + Thread.currentThread().getName());
//        }, 5, TimeUnit.SECONDS);

        //延时时间后，开始固定频率(假如说前一个任务在间隔时间内没有执行完成，则下一个任务会在前一个任务执行完成立即执行)的无限次执行任务，计时时间是从任务开始时间来计算的。
        /**
         * 参数含义
         * param1 执行的任务
         * param2 延时的时间
         * param3 任务执行的间隔时间
         * param4  param3和param4的时间单位
         */
//        threadPool.scheduleAtFixedRate(() -> {
//            System.out.println(LocalDateTime.now() + "线程名称：" + Thread.currentThread().getName());
//            try {
//                TimeUnit.SECONDS.sleep(6);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }, 3, 5, TimeUnit.SECONDS );
          //固定延时时间执行任务，它的延时时间是在任务执行完后开始计算的。在定时任务开始后，每隔固定时间就开始执行下一个任务，会在任务执行完后，再等待间隔时间后再开始下一个任务。
        /**
         * 参数含义
         * param1 执行的任务
         * param2 延时的时间
         * param3 任务执行的间隔时间
         * param4  param3和param4的时间单位
         */
        threadPool.scheduleWithFixedDelay(() -> {
            System.out.println(LocalDateTime.now() + "线程名称：" + Thread.currentThread().getName());
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, 3, 5, TimeUnit.SECONDS);
    }

    public static void singleThreadScheduledExecutor() {

        //创建只有单个线程的可以执行延时任务的线程池
        ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
        System.out.println(LocalDateTime.now() + "开始执行");
        //使用线程池执行任务
        threadPool.schedule(() -> {
            System.out.println(LocalDateTime.now() + "线程名称：" + Thread.currentThread().getName());
        }, 3, TimeUnit.SECONDS);

    }

    public static void newWorkStealingPool() {
        //该线程池的特点是可以抢占任务，会把待执行任务分配给可用的工作线程，如果有线程先完成了分配的任务就会去帮助别的线程处理任务，知道所有任务完成，
        // 这样可以减少线程的空闲时间，更高效的完成任务，所以比较耗时的任务比较适合用这个线程池
        //创建抢占式线程池,java版本至少是1.8
        ExecutorService threadPool = Executors.newWorkStealingPool();
        //开始安排任务时间
        System.out.println(LocalDateTime.now() + "开始执行");
        //使用线程池执行任务
        for (int i = 0; i < 30; i++) {
            final int index = i;
            threadPool.execute(() -> {
                System.out.println(index + " " + LocalDateTime.now() + "线程名称" + Thread.currentThread().getName());
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

        }

        // 确保任务执行完成
        while (!threadPool.isTerminated()) {
        }
    }
}
